// <com.woyouqiu.Copyright>
// --------------------------------------------------------------
// <copyright>上海有求网络科技有限公司 2015</copyright>
// <Solution>MyCompany.MyProject</Solution>
// <Project>MyCompany.MyProject.Application</Project>
// <FileName>AgentAppService.cs</FileName>
// <CreateTime>2017-04-25 16:20</CreateTime>
// <Author>何苗</Author>
// <Email>hemiao@woyouqiu.com</Email>
// <log date="2017-04-25 16:20" version="00001">创建</log>
// --------------------------------------------------------------
// </com.woyouqiu.Copyright>

using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using Abp.UI;
using Vecen.BangChuang.Authorization.Users;
using Vecen.BangChuang.BangChuang.Agents.Dtos;
using Vecen.BangChuang.BangChuang.Areas;
using Vecen.BangChuang.BangChuang.Areas.DomainDtos;
using Vecen.BangChuang.BangChuang.DomainServices.Agents;
using Vecen.BangChuang.BangChuang.DomainServices.EventHandlers.EventDatas;

namespace Vecen.BangChuang.BangChuang.Agents {
    /// <summary>
    /// 店长操作
    /// </summary>
    [AbpAuthorize()]
    public class AgentAppService: BangChuangAppServiceBase, IAgentAppService {
        private readonly IRepository<Agent> _agentRepository;
        private readonly IRepository<AgentApply> _agentApplyRepository;
        private readonly CityDomainService _cityDomainService;
        private readonly IRepository<AgentClient> _agentClientRepository;
        private readonly AgentDomainService _agentDomainService;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="agentRepository"></param>
        /// <param name="cityDomainService"></param>
        /// <param name="agentApplyRepository"></param>
        /// <param name="agentClientRepository"></param>
        /// <param name="agentDomainService"></param>
        public AgentAppService(IRepository<Agent> agentRepository,
            CityDomainService cityDomainService,
            IRepository<AgentApply> agentApplyRepository,
            IRepository<AgentClient> agentClientRepository,
            AgentDomainService agentDomainService) {
            _agentRepository = agentRepository;
            _cityDomainService = cityDomainService;
            _agentApplyRepository = agentApplyRepository;
            _agentClientRepository = agentClientRepository;
            _agentDomainService = agentDomainService;
        }

        /// <summary>
        /// 根据店长ID获得店长信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [AbpAllowAnonymous]
        public async Task<AgentOutDto> GetByIdAsync(int id) {
            var agent = await _agentRepository.FirstOrDefaultAsync(id);
            if(agent == null)
                throw new UserFriendlyException("请求失败!", "指定的店长不存在!");
            return await MapOutDto(agent);
        }

        private async Task<AgentOutDto> MapOutDto(Agent agent) {

            var agentUser = await UserManager.AbpStore.FindByIdAsync(agent.UserId.ToString());
            var dto = new AgentOutDto();
            dto.Id = agent.Id;
            dto.Name = agentUser.Name;
            dto.PhoneNumber = agentUser.PhoneNumber;
            dto.WeChat = agentUser.WeChat;
            dto.IsActive = agent.IsActive;
            dto.UserType = agent.UserType;
            dto.Address = await _cityDomainService.GetFullAddressDtoByCityId(agent.AreaCode);
            dto.UserAvatarId = await AttachmentManager.GetIdAsync(User.UserAvatarAttachmentType, agentUser.Id);
            return dto;
        }

        /// <summary>
        /// 根据城市地区ID获得店长
        /// </summary>
        /// <param name="cityId"></param>
        /// <returns></returns>
        public async Task<AgentOutDto> GetByCityIdAsync(int cityId) {
            var agent = await _agentRepository.FirstOrDefaultAsync(c => c.AreaCode == cityId);
            if(agent == null) {
                throw new UserFriendlyException("请求失败!", "该地区还没有店长信息!");
            }
            return await MapOutDto(agent);
        }

        /// <summary>
        /// 获得我的店长列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ListResultDto<AgentOutDto>> GetAgentsAsync(GetAgentsRequestDto input) {
            var agent = _agentDomainService.GetByUserIdAsync(AbpSession.GetUserId());
            if(agent == null) {
                throw new UserFriendlyException("请求失败!", "您还不是店长!");
            }
            var query = _agentRepository.GetAllIncluding(c => c.User)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(),
                    c => c.User.PhoneNumber.Contains(input.Keyword) || c.User.Name.Contains(input.Keyword)
                         || c.User.WeChat.Contains(input.Keyword))
                .Where(c => c.ParentAgentId == agent.Id);

            var agents = await Task.Run(() => query.ToList());
            var list = new List<AgentOutDto>();
            foreach(var childAgent in agents) {
                list.Add(await MapOutDto(childAgent));
            }

            return new ListResultDto<AgentOutDto>(list);
        }

        /// <summary>
        /// 获得店长列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<AgentOutDto>> GetAgentsForAdminAsync(GetAgentsForAdminInputDto input) {
            var query = _agentRepository.GetAllIncluding(c => c.User)
                .WhereIf(!input.UserType.IsNullOrWhiteSpace(), c => c.UserType == input.UserType)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(),
                    c => c.User.PhoneNumber.Contains(input.Keyword) || c.User.Name.Contains(input.Keyword)
                         || c.User.WeChat.Contains(input.Keyword));
            var total = await Task.Run(() => query.Count());
            var agents = await Task.Run(() => query.OrderBy(input.Sorting).PageBy(input).ToList());
            var list = new List<AgentOutDto>();
            foreach(var childAgent in agents) {
                list.Add(await MapOutDto(childAgent));
            }

            return new PagedResultDto<AgentOutDto>(total, list);
        }

        /// <summary>
        /// 升级普通用户为店长
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpgradeUserToAgentAsync(UpgradeUserToAgentRequestDto input) {
            var agent = await _agentRepository.FirstOrDefaultAsync(c => c.UserId == input.UserId);
            if(agent != null) {
                throw new UserFriendlyException("请求失败!", "该用户已经是店长了!");
            }

            var isExistsApply = await _agentApplyRepository.FirstOrDefaultAsync(c => c.UserId == input.UserId);
            if(isExistsApply != null) {
                throw new UserFriendlyException("请求失败!", "该用户已经处于待确认状态!无需再次提交!");
            }
            var areaCode = _cityDomainService.GetAreaId(input.ProvinceId, input.CityId, input.DistrictId);
            agent = await _agentRepository.FirstOrDefaultAsync(c => c.AreaCode == areaCode);
            if(agent != null) {
                throw new UserFriendlyException("请求失败!", "该地区已经存在店长,请先取消!");
            }

            var user = await UserManager.GetUserByIdAsync(input.UserId);
            if(string.IsNullOrWhiteSpace(input.UserType)) {
                input.UserType = UserType.SecondAgentUser;
            }

            var apply = new AgentApply();
            apply.UserId = input.UserId;
            apply.Name = user.Name;
            apply.PhoneNumber = user.PhoneNumber;
            apply.Wechat = user.WeChat;
            apply.AreaCode = areaCode;
            apply.UserType = input.UserType;
            apply.ParentAgentId = input.ParentAgentId;

            apply.UniversityName = input.UniversityName;
            apply.IsStudent = input.IsStudent;
            apply.CollegeName = input.CollegeName;
            await _agentApplyRepository.InsertAndGetIdAsync(apply);
        }


        /// <summary>
        /// 申请升级为店长
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ApplyUpdateToAgentAsync(ApplyUpdateToAgentRequestDto input) {
            var agent = await _agentRepository.FirstOrDefaultAsync(c => c.UserId == AbpSession.UserId);
            if(agent != null) {
                throw new UserFriendlyException("请求失败!", "你已经是店长了，不用在申请了！");
            }
            var agentApply = await _agentApplyRepository.FirstOrDefaultAsync(c => c.UserId == AbpSession.UserId);
            if(agentApply == null) {
                throw new UserFriendlyException("请求失败!", "您还未得到上级店长通知,不能申请！");
            }

            var apply = input.MapTo<AgentApply>();
            apply.AreaCode =
                agentApply.AreaCode; // _cityDomainService.GetAreaId(input.ProvinceId, input.CityId, input.DistrictId);
            apply.Id = agentApply.Id;
            apply.IsConfirmed = true;
            await _agentApplyRepository.UpdateAsync(apply);

            await EventBus.TriggerAsync(new AgentApplyPassedEventData {ApplyId = apply.Id});
        }

        /// <summary>
        /// 获得我的客户
        /// </summary>
        /// <returns></returns>
        public async Task<PagedResultDto<AgentClientOutDto>> GetMyClientAsync(GetMyClientRequestDto input) {
            var agent = await _agentDomainService.GetByUserIdAsync(AbpSession.GetUserId());
            if(agent == null) {
                throw new UserFriendlyException("请求失败!", "您还不是店长,无权查看此信息!");
            }
            var query = _agentClientRepository.GetAllIncluding(c => c.User)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(),
                    c => c.User.Name.Contains(input.Keyword) || c.User.PhoneNumber.Contains(input.Keyword)
                         || c.User.WeChat.Contains(input.Keyword))
                .Where(c => c.AgentId == agent.Id);

            var total = await Task.Run(() => query.Count());
            var clients = await Task.Run(() => query.PageBy(input).OrderBy(input.Sorting).ToList());
            List<AgentClientOutDto> dtos = new List<AgentClientOutDto>();
            foreach(var client in clients) {
                var dto = new AgentClientOutDto {
                    Id = client.Id, AgentId = client.AgentId, ClientId = client.UserId, ClientName = client.User.Name,
                    PhoneNumber = client.User.PhoneNumber, WeChat = client.User.WeChat
                };
                if(client.User.AreaCode.HasValue) {
                    dto.Address = (await _cityDomainService.GetFullAddressByCityId(client.User.AreaCode.Value))
                        .MapTo<FullCityOutDto>();
                }
                dto.AvatarId = await AttachmentManager.GetIdAsync(User.UserAvatarAttachmentType, client.UserId);
                dtos.Add(dto);
            }
            return new PagedResultDto<AgentClientOutDto>(total, dtos);
        }

        /// <summary>
        /// 修改店长资料
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateAgentProfileAsync(AgentProfileInputDto input) {
            var agent = await _agentRepository.FirstOrDefaultAsync(input.Id);
            if(agent == null) {
                throw new UserFriendlyException("修改店长资料失败!", "店长数据不存在!");
            }
            agent.AreaCode = _cityDomainService.GetAreaIdNotNull(input.ProvinceId, input.CityId, input.DistrictId);
            agent.IsStudent = input.IsStudent;
            agent.UniversityName = input.UniversityName;
            agent.CollegeName = input.CollegeName;
            await _agentRepository.UpdateAsync(agent);
        }

        /// <summary>
        /// 吊销店长资格
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task RevokeAgentAsync(EntityDto input) {
            await _agentRepository.DeleteAsync(input.Id);
        }

        /// <summary>
        /// 获取未确认的店长升级记录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<AgentApplyListDto>>
            GetNoConfirmedApplyAsync(GetNoConfirmedApplyInputDto input) {
            var query = _agentApplyRepository.GetAll()
                .Where(c => c.IsConfirmed == false)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(),
                    c => c.Name.Contains(input.Keyword) || c.PhoneNumber.Contains(input.Keyword))
                .WhereIf(!input.AgentType.IsNullOrWhiteSpace(), c => c.UserType == input.AgentType);
            var total = await Task.Run(() => query.Count());
            var list = await Task.Run(() => query.OrderBy(input.Sorting).PageBy(input).ToList());


            return new PagedResultDto<AgentApplyListDto>(total, list.MapTo<List<AgentApplyListDto>>());
        }

        /// <summary>
        /// 撤销待确认的店长
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task RevokeAgentApplyAsync(EntityDto input) {
            await _agentApplyRepository.DeleteAsync(input.Id);
        }

        /// <summary>
        /// 直接升级待确认的店长
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task NoNeedConfirmApplyAsync(EntityDto input) {
            var apply = await _agentApplyRepository.FirstOrDefaultAsync(input.Id);
            apply.IsConfirmed = true;
            await _agentApplyRepository.UpdateAsync(apply);

            await EventBus.TriggerAsync(new AgentApplyPassedEventData {ApplyId = apply.Id});
        }

        /// <summary>
        /// 获得当前店长标识
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetAgentPrimaryKey() {
            var agent = await _agentDomainService.GetByUserIdAsync(AbpSession.GetUserId());
            return await _agentDomainService.GetAgentPrimaryKey(agent);
        }

        /// <summary>
        /// 获得所有店长的学校名称(去重)
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<string>> GetUniversityNamesAsync() {
            return new ListResultDto<string>(await Task.Run(() => _agentRepository.GetAll()
                .Select(c => c.UniversityName)
                .Distinct()
                .ToList()));
            ;
        }
    }
}